#ifndef FORMIC_LED_HAM_ACTOR_HUBB_HEADER
#define FORMIC_LED_HAM_ACTOR_HUBB_HEADER

#include<pthread.h>
#include<vector>

#include<formic/matrix_actor.h>
#include<formic/lattice_ed/configuration.h>

namespace formic {

namespace led {

  template <class SCALAR> void * thread_func_hubb(void * arg);

  template <class SCALAR> class HamActorHubb : public formic::MatrixActor<SCALAR> {

    private:

      /// \brief  the number of configurations per spin orbital (which is just 2)
      int _cps;

      /// \brief  the number of threads to use
      int _nthread;

      /// \brief  the number of sites
      int _ns;

      /// \brief  the number of alpha electrons
      int _na;

      /// \brief  the number of beta electrons
      int _nb;

      /// \brief  hubbard onsite repulsion strengths
      std::vector<double> _uvec;

      /// \brief  threshold for convergence
      double _thresh;

      /// \brief  z arrays table used in index computation for alpha
      std::vector<int> _z_array_a;

      /// \brief  z array lookup table used in index computation for alpha
      std::vector<int> _z_lookup_a;

      /// \brief  offests used in index computation for alpha
      std::vector<int> _offsets_a;

      /// \brief  spacings used in index computation for alpha
      std::vector<int> _spacing_a;

      /// \brief  z arrays table used in index computation for beta
      std::vector<int> _z_array_b;

      /// \brief  z array lookup table used in index computation for beta
      std::vector<int> _z_lookup_b;

      /// \brief  offests used in index computation for beta
      std::vector<int> _offsets_b;

      /// \brief  spacings used in index computation for beta
      std::vector<int> _spacing_b;

      /// \brief  integer workspace used in index computation
      std::vector<int> _work;

      /// \brief  bond indices
      std::vector<int> _bonds;

      /// \brief  bond operator coefficients
      std::vector<double> _bond_strengths;

      /// \brief  alpha starting configurations for the different threads
      std::vector<formic::led::Configuration> _start_configs_a;

      /// \brief  compound indices of each thread's end alpha configuration
      std::vector<int> _end_cmpds_a;

      /// \brief  beta starting configurations for the different threads
      std::vector<formic::led::Configuration> _start_configs_b;

      /// \brief  compound indices of each thread's end beta configuration
      std::vector<int> _end_cmpds_b;

      /// \brief  space for the threads to store their multiplication results
      std::vector<SCALAR> _thread_workspace;

      /// \brief  pointers to each thread's storage space
      std::vector<SCALAR *> _thread_work_ptrs;

    public:

      // function to return the name of the child class
      std::string class_name() { return "formic::led::HamActorHubb"; }

      // constructor
      HamActorHubb(const int ns,
                   const int na,
                   const int nb,
                   const std::vector<double> & uvec,
                   const std::vector<int> & bonds,
                   const std::vector<double> & bond_strengths,
                   const int nthread,
                   const double thresh);

      // function to perform y = A d
      void operate(const int n, SCALAR * const d, SCALAR * const y, const int myrank, const int tid);

      struct ThreadArgs {
        int tid;
        int myrank;
        formic::led::HamActorHubb<SCALAR> * obj_ptr;
        pthread_mutex_t * mtx_ptr;
        int n;
        const SCALAR * d;
        SCALAR * y;
      };

      friend void * formic::led::thread_func_hubb<SCALAR>(void *);

  };

}

}

#endif
